using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Xml; // some comments
using System.Net; // just added to test some diffing
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.Collections.Generic;
using Ltf.Remoting.Settings;
using Ltf.Remoting.RemoteEvents;
using Ltf.Remoting.TeamFoundation;
using System.Threading;
using Ltf.Remoting.Commands;
using Ltf.Remoting.TFAccess;
using Ltf.MonitorLizard.Helpers;
using System.Reflection;
using Ltf.Diffs;
using Ltf.Remoting.Operations;
using System.Collections;
using System.Text;
using Ltf.Diffs.MergeCommands;
using Ltf.MonitorLizard.Controls;
using Ltf.MonitorLizard.Controllers;
// some comment
namespace Ltf.MonitorLizard.Forms
{
	[FormType(FormTypes.FolderDiff)]
	public partial class DirDiff : Form
	{
		private XmlNode _selectedNode;

		private ChangesetListController changesetListController;
		private ChangesetFilesListController changesetFilesListController;

		public DirDiff(string path1, string path2, TFServerConnection connection1, TFServerConnection connection2)
			: this()
		{
			try
			{
				if (path1.StartsWith("$"))
				{
					int v;
					string name;
					LizardFileAccess.GetNameAndVersionFromPath(path1, out name, out v, out deletionId1);
					txtPath1.Text = name;
					cmbVersion1.Text = v.ToString();
					this.sselConnection1.Connection = connection1;
				}
				else
				{
					if (File.Exists(path1))
						path1 = Path.GetDirectoryName(path1);
					txtPath1.Text = path1;
					sselConnection1.Connection = ServerConnections.GetConnectionForPath(path1);
				}
				if (path2.StartsWith("$"))
				{
					int v;
					string name;
					LizardFileAccess.GetNameAndVersionFromPath(path2, out name, out v, out deletionId2);
					txtPath2.Text = name;
					cmbVersion2.Text = v.ToString();
					this.sselConnection2.Connection = connection2;
				}
				else
				{
					if (File.Exists(path2))
						path2 = Path.GetDirectoryName(path2);
					txtPath2.Text = path2;
					sselConnection2.Connection = ServerConnections.GetConnectionForPath(path2);
				}
			}
			catch (Exception ex)
			{
				//				File.WriteAllText(ServerConnections.DefaultConnection.Settings.TempPath + "DirDiffContructor.txt", string.Format("Exception:{0}\r\nTrace:\rn\r{1}", ex.Message, ex.StackTrace));

			}
			historySelector1 = new HistorySelector(cmbVersion1, sselConnection1.Connection, workspace1);
			historySelector2 = new HistorySelector(cmbVersion2, sselConnection2.Connection, workspace2);

		}


		public DirDiff(string[] paths, LizardEventArgs args)
			: this()
		{
			try
			{
				string path = paths[0];
				if (File.Exists(path))
					path = Path.GetDirectoryName(path);
				txtPath1.Text = path;
				sselConnection1.Connection = ServerConnections.GetConnectionForPath(path);
				sselConnection2.Connection = sselConnection1.Connection;
				VersionControlServer vcServer = sselConnection1.Connection.VersionControlServer;
				workspace1 = vcServer.GetWorkspace(path);
				workspace2 = workspace1;
				if (workspace1 != null)
					txtPath2.Text = workspace1.GetServerItemForLocalItem(path);


				historySelector1 = new HistorySelector(cmbVersion1, sselConnection1.Connection, workspace1);
				historySelector2 = new HistorySelector(cmbVersion2, sselConnection2.Connection, workspace2);

			}
			catch (Exception ex)
			{
				string m = ex.Message;
				//			File.WriteAllText(ServerConnections.DefaultConnection.Settings.TempPath+"DirDiffContructor.txt", string.Format("Exception:{0}\r\nTrace:\rn\r{1}", ex.Message, ex.StackTrace));

			}
		}

		public DirDiff()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

			SetChangeSetPanelRight();

			swcCaption.Text = "ChangeSet Files";


			changesetListController = new ChangesetListController(lvwHistory, true);
			changesetFilesListController = new ChangesetFilesListController(lvwDetails, false);

			changesetListController.AfterMultiSelection += new EventHandler(changesetListController_AfterMultiSelection);

			trvDifResults.MouseUp += new MouseEventHandler(trvDifResults_MouseUp);

			this.Closing += new CancelEventHandler(Form1_Closing);

			PersistableHashtable pht = new PersistableHashtable();


			txtPath1.DragDrop += new DragEventHandler(pathBox_DragDrop);
			txtPath1.DragOver += new DragEventHandler(pathBox_DragOver);
			txtPath2.DragDrop += new DragEventHandler(pathBox_DragDrop);
			txtPath2.DragOver += new DragEventHandler(pathBox_DragOver);

			if (pht.Contains("ToPath")) txtPath1.Text = pht["ToPath"].ToString();
			if (pht.Contains("FromPath")) txtPath2.Text = pht["FromPath"].ToString();

			if (pht.Contains("ShowAllPaths")) ckbShowAllPaths.Checked = bool.Parse(pht["ShowAllPaths"].ToString());
			if (pht.Contains("ShowDiffs")) ckbShowDiffs.Checked = bool.Parse(pht["ShowDiffs"].ToString());
			if (pht.Contains("ShowMissing")) ckbShowMissing.Checked = bool.Parse(pht["ShowMissing"].ToString());
			if (pht.Contains("ShowSames")) ckbShowSames.Checked = bool.Parse(pht["ShowSames"].ToString());
			if (pht.Contains("ShowAdded")) ckbShowSames.Checked = bool.Parse(pht["ShowAdded"].ToString());
			if (pht.Contains("ShowDiffMetrics")) ckbShowDiffMetrics.Checked = bool.Parse(pht["ShowDiffMetrics"].ToString());
			if (pht.Contains("ShowFullPaths")) ckbShowFullPaths.Checked = bool.Parse(pht["ShowFullPaths"].ToString());
			if (pht.Contains("ShowTotals")) ckbShowTotals.Checked = bool.Parse(pht["ShowTotals"].ToString());
			if (pht.Contains("UserChecks")) ckbUserChecks.Checked = bool.Parse(pht["UserChecks"].ToString());
			if (pht.Contains("IgnoreBlankLines")) ckbIgnoreBlankLines.Checked = bool.Parse(pht["IgnoreBlankLines"].ToString());
			if (pht.Contains("IgnoreCase")) ckbIgnoreCase.Checked = bool.Parse(pht["IgnoreCase"].ToString());
			if (pht.Contains("IgnoreSpaceChanges")) ckbIgnoreSpaceChanges.Checked = bool.Parse(pht["IgnoreSpaceChanges"].ToString());
			if (pht.Contains("IgnoreTabExpansions")) ckbIgnoreTabExpansions.Checked = bool.Parse(pht["IgnoreTabExpansions"].ToString());
			if (pht.Contains("IgnoreWhiteSpace")) ckbIgnoreWhiteSpace.Checked = bool.Parse(pht["IgnoreWhiteSpace"].ToString());

		}



		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				if (components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose(disposing);
		}



		private void cbtPath1_Click(object sender, EventArgs e)
		{
			GetPath(txtPath1);
		}

		private void cbtPath2_Click(object sender, EventArgs e)
		{
			GetPath(txtPath2);
		}

		private void GetPath(TextBox ResultBox)
		{
			GetPath(ResultBox, "");
		}

		private void GetPath(TextBox resultBox, string commonPath)
		{
			FolderBrowserDialog fbd = new FolderBrowserDialog();
			if (Directory.Exists(commonPath + resultBox.Text))
			{
				fbd.SelectedPath = commonPath + resultBox.Text;
			}
			else
			{
				fbd.SelectedPath = commonPath;
			}
			try
			{
				fbd.ShowDialog();
			}
			catch (Exception e)
			{
				string s = fbd.SelectedPath;
			}
			resultBox.Text = fbd.SelectedPath.Substring(commonPath.Length);
		}

		private void GetTFPath(TextBox resultBox, ComboBox versionBox, Workspace workspace, out TFServerConnection connection)
		{
			string path = resultBox.Text;
			int v;
			if (int.TryParse(versionBox.Text, out v))
			{
				path =LizardFileAccess.SetPathVersion(path, v);
			}

			TFProjectBrowser tfpb = new TFProjectBrowser(path, workspace);
			tfpb.ShowDialog();

			string name;
			LizardFileAccess.GetNameAndVersionFromPath(tfpb.ProjectPath, out name, out v);
			resultBox.Text = name;
			versionBox.Text = tfpb.ProjectVersion == 0 ? "Latest" : tfpb.ProjectVersion.ToString();
			connection = tfpb.Connection;
		}


		private void cbtCompare_Click(object sender, EventArgs e)
		{
			Compare();
		}

		ProgressIndicator progressIndicator;
		DirDiffer Differ;

		bool isComparing = false;

		public void Compare()
		{
			string[] oldNames = { };
			string[] newNames = { };

			if (ckbTrackRenames.Visible && ckbTrackRenames.Checked)
			{
				string[][] renames = GetRenames();
				oldNames = renames[1];
				newNames = renames[0];

			}


			RunDiffer(false, oldNames, newNames, null);

			tabControl1.TabPages[1].Select();
		}

		

		void differ_Finished(object sender, EventArgs e)
		{
			isComparing = false;
			// this event will have been raised by the process thread
			// so we'll need a control Invoke to get back to the forms thread
			// in order to actaully reflect any results.
			this.Invoke(new EventHandler(ShowDifResults));
		}

		void ShowDifResults(object sender, EventArgs e)
		{
			this.Cursor = Cursors.Default;
			if (progressIndicator != null)
				progressIndicator.Close();

			if (Differ != null)
			{
				if (Differ.Results != null)
					ShowTree(Differ.Results);

				if (savePatchOnFinish && !string.IsNullOrEmpty(patchFileName))
					File.WriteAllText(patchFileName, Differ.PatchFile);

				if (isPrepareMerge && rbtLizardMerge.Checked)
				{
					File.WriteAllText("c:\\dryruntest.diff", Differ.PatchFile);

					PrepareMerge(Differ.PatchFile, txtLtfMergeTarget.Text);
				}
			}
			savePatchOnFinish = false;
			patchFileName = string.Empty;
		}

		Dictionary<string[], string> diffResults = new Dictionary<string[], string>();
		DifferenceInfos diffInfos = new DifferenceInfos();

		private string GetStringCountForListView(int count)
		{
			if (count == -1)
				return "File";
			else if (count == 0)
				return string.Empty;
			else
				return count.ToString();
		}

		private void PrepareMerge(string diffFile, string ltfMergeTarget)
		{
			bool trackRenames = (ckbTrackRenames.Visible && ckbTrackRenames.Checked);
			diffInfos = new DifferenceInfos(sselConnection1.Connection, workspace1, mergePath2, MergeChangeSetVersionFrom,
				mergePath1, MergeChangeSetVersionTo,
				mergeTargetPath, diffFile, Differ, trackRenames);

			ShowAllDiffInfos();
		}

		private void ShowAllDiffInfos()
		{
			int mergeableFiles = 0, conflictedFiles = 0, existingChangedFiles = 0;
			lsvMergeResults.Items.Clear();

			foreach (DifferenceInfo diffInfo in diffInfos)
			{
				ListViewItem lvi = new ListViewItem(new string[] {diffInfo.OldName , diffInfo.ItemTargetPath,
						GetStringCountForListView(diffInfo.Inserts),
						GetStringCountForListView(diffInfo.Changes), 
						GetStringCountForListView(diffInfo.Deletes), 
						GetStringCountForListView(diffInfo.Conflicts), 
						GetStringCountForListView(diffInfo.AllExisting), 
						diffInfo.NewName, diffInfo.MergeCommands.ShortNames });

				bool conflict = false;

				conflict |= (diffInfo.Conflicts != 0);


				if (conflict)
				{
					lvi.ImageKey = diffInfo.RenameConflict ? "DoubleConflict2.bmp" : "ChangeConflict.bmp";
					if (diffInfo.Inserts == -1)
						lvi.ImageKey = "AddConflict.bmp";
					else if (diffInfo.Deletes == -1)
						lvi.ImageKey = "DeleteConflict.bmp";
					lvi.ForeColor = Color.Tomato;
					conflictedFiles++;
				}
				else
				{
					if (diffInfo.Inserts == -1)
						lvi.ImageKey = "add.bmp";
					else if (diffInfo.Deletes == -1)
						lvi.ImageKey = "delete.bmp";
					else
						lvi.ImageKey = "changed.bmp";
					if (diffInfo.AllExisting != 0 && diffInfo.AllChanges == 0 && diffInfo.Conflicts == 0)
					{
						lvi.ImageKey = "allexisting.bmp";
						existingChangedFiles++;
					}
					else
					{
						mergeableFiles++;
					}
					if (diffInfo.AllExisting != 0 && diffInfo.AllChanges == 0)
						lvi.ForeColor = Color.DarkBlue;
					else if (diffInfo.Conflicts == 0)
						lvi.ForeColor = Color.DarkGreen;
				}
				if (diffInfo.Resolved)
				{
					lvi.ForeColor = Color.PowderBlue;
					lvi.Font = new Font(lvi.Font, FontStyle.Strikeout);
				}
				lvi.Tag = diffInfo;
				if (chkAllChangedFiles.Checked || lvi.ImageKey != "allexisting.bmp")
					lsvMergeResults.Items.Add(lvi);
			}

			tsslMergeable.Text = string.Format("Mergeable Changed Files : {0}", mergeableFiles); ;
			tsslConflictingChanges.Text = string.Format("Conflicted Changed Files : {0}", conflictedFiles); ;
			tsslExisting.Text = string.Format("Existing Changed Files : {0}", existingChangedFiles); ;
			tabControl1.SelectedTab = tabControl1.TabPages[2];

		}

		
		private void ShowTree(XmlDocument diffResults)
		{
			if (!isComparing)
			{
				trvDifResults.Nodes.Clear();
				trvDifResults.CheckBoxes = ckbUserChecks.Checked;
				TreeNode tn = new TreeNode("");
				trvDifResults.Nodes.Add(tn);
				if (diffResults != null)
				{
					RecurseAddNode(diffResults.FirstChild, trvDifResults.Nodes[0]);
				}
				tn.ExpandAll();
			}
		}

		private void RecurseAddNode(XmlNode diffNode, TreeNode displayNode)
		{
			string na = (ckbShowFullPaths.Checked) ? "FileFullName" : "FileName";
			if (ckbShowDiffs.Checked)
			{
				foreach (XmlNode cn in diffNode.SelectNodes("FileDiff|FileConflict"))
				{
					int imageIdx = cn.LocalName == "FileDiff" ? 6 : 13;
					TreeNode tn = new TreeNode(cn.Attributes[na].Value, imageIdx, imageIdx);
					tn.Tag = cn.Attributes["NodeIndex"].Value;
					displayNode.Nodes.Add(tn);
				}
			}
			if (ckbShowSames.Checked)
			{
				foreach (XmlNode cn in diffNode.SelectNodes("FileSame"))
				{
					TreeNode tn = new TreeNode(cn.Attributes[na].Value, 4, 4);
					tn.Tag = cn.Attributes["NodeIndex"].Value;
					displayNode.Nodes.Add(tn);
				}
			}
			if (ckbShowMissing.Checked)
			{
				foreach (XmlNode cn in diffNode.SelectNodes("FileMissing"))
				{
					TreeNode tn = new TreeNode(cn.Attributes[na].Value, 8, 8);
					tn.Tag = cn.Attributes["NodeIndex"].Value;
					displayNode.Nodes.Add(tn);
				}
			}
			if (ckbShowAdded.Checked)
			{
				foreach (XmlNode cn in diffNode.SelectNodes("FileAdded|SameFileAdded"))
				{
					TreeNode tn = new TreeNode(cn.Attributes[na].Value, 5, 5);
					tn.Tag = cn.Attributes["NodeIndex"].Value;
					displayNode.Nodes.Add(tn);
				}
			}
			foreach (XmlNode cn in diffNode.SelectNodes("FileError"))
			{
				TreeNode tn = new TreeNode("Error : " + cn.Attributes[na].Value, 15, 15);
				tn.Tag = cn.Attributes["NodeIndex"].Value;
				displayNode.Nodes.Add(tn);
			}

			foreach (XmlNode cn in diffNode.SelectNodes("DiffPath"))
			{
				if (cn.ChildNodes.Count > 0 || ckbShowAllPaths.Checked)
				{
					string metrics = "(Diff=" + cn.SelectNodes("FileDiff").Count + ", Same=" + cn.SelectNodes("FileSame").Count + ", Missing=" + cn.SelectNodes("FileMissing").Count + ")";
					//					string totals = "Dirs=" + cn.Attributes["DirDirTotal"].Value + ", Files=" + cn.Attributes["DirFilesTotal"].Value;
					string totals = "no totals available";
					string dirtype = cn.Attributes["DirDiff"].Value;
					int imgNo = 0;
					switch (dirtype.ToLower())
					{
						case "dirdiff":
							imgNo = 11;
							break;
						case "dirconflict":
							imgNo = 14;
							break;
						case "dirsame":
							imgNo = 9;
							break;
						case "diradded":
							imgNo = 10;
							break;
						case "dirmissing":
							imgNo = 12;
							break;
					}
					TreeNode tn = new TreeNode(cn.Attributes[(ckbShowFullPaths.Checked) ? "DirFullName" : "DirName"].Value + ((ckbShowTotals.Checked) ? "            " + totals : "") + ((ckbShowDiffMetrics.Checked) ? "            " + metrics : ""), imgNo, imgNo);
					tn.Tag = cn.Attributes["NodeIndex"].Value;

					displayNode.Nodes.Add(tn);
					RecurseAddNode(cn, tn);
					if (tn.Nodes.Count == 0 && !ckbShowAllPaths.Checked)
					{
						displayNode.Nodes.Remove(tn);
					}
					else
					{
						tn.ExpandAll();
					}
				}
			}
		}

		private void ckbAny_CheckedChanged(object sender, EventArgs e)
		{
			if (Differ != null)
				ShowTree(Differ.Results);
		}



		//private void differ_DiffAnotherTen(object sender, EventArgs e)
		//{
		//  _done += 10;
		//  sbProgress.Text = "Done:" + _done.ToString();
		//}


		private void trvDifResults_AfterSelect(object sender, TreeViewEventArgs e)
		{
			if (Differ != null)
				_selectedNode = Differ.Results.SelectSingleNode("//*[@NodeIndex='" + trvDifResults.SelectedNode.Tag + "']");
		}

		private void trvDifResults_MouseUp(object sender, MouseEventArgs e)
		{
			TreeNode tn = trvDifResults.GetNodeAt(e.X, e.Y);
			if (tn == null) return;
			_selectedNode = Differ.Results.SelectSingleNode("//*[@NodeIndex='" + tn.Tag + "']");
			if (e.Button == MouseButtons.Right && _selectedNode != null)
			{
				if (_selectedNode.LocalName == "FileMissing")
				{
					cmiEditFrom.Enabled = true;
					cmiEditTo.Enabled = false;
					cmiShowGnu.Enabled = false;
					cmiShowWindiff.Enabled = false;
				}
				else if (_selectedNode.LocalName == "FileAdded")
				{
					cmiEditFrom.Enabled = false;
					cmiEditTo.Enabled = true;
					cmiShowGnu.Enabled = false;
					cmiShowWindiff.Enabled = false;
				}
				else
				{
					cmiEditFrom.Enabled = true;
					cmiEditTo.Enabled = true;
					cmiShowGnu.Enabled = true;
					cmiShowWindiff.Enabled = true;
				}
				ShowTreeContextMenu(new Point(e.X, e.Y));
			}
		}

		private void ShowTreeContextMenu(Point location)
		{
			cmDiffFileNode.Show(trvDifResults, location);
		}

		private void menuItem6_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		private void cbtExit_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		private void cmiShowWindiff_Click(object sender, EventArgs e)
		{
			try
			{
				string fn = _selectedNode.Attributes["FileFullName"].Value;

				string path1 = _selectedNode.Attributes["ToFilePath"].Value;
				string path2 = _selectedNode.Attributes["FromFilePath"].Value;

				string ext = Path.GetExtension(path1);
				if (ext == ".dll" || ext == ".exe" || ext.StartsWith(".dll;") || ext.StartsWith(".exe;"))
				{
					Ltf.MonitorLizard.Forms.ExecutableDiff ed = new Ltf.MonitorLizard.Forms.ExecutableDiff(path2, path1);
					ed.Show();
				}
				else
				{
					Ltf.MonitorLizard.Forms.TwoWayDiff twd = new Ltf.MonitorLizard.Forms.TwoWayDiff(path2, path1, workspace2, workspace1);
					twd.CompareSideBySide(path2, path1);
					twd.Show();
				}

			}
			catch
			{
				MessageBox.Show("Could not launch specified diff utility.", "LizardTF Diff");
			}

		}

		private string RegenerateOriginalPath(string basePath, string filePath)
		{
			string seperator = ((basePath.StartsWith("$")) ? "/" : "\\");

			string path1 = basePath + seperator + GetPathEnd(basePath, filePath);

			if (path1.Contains("["))
				path1 = path1.Substring(0, path1.IndexOf('[') - 1);


			int v;
			if (path1.StartsWith("$") & int.TryParse(cmbVersion1.Text, out v))
				path1 = LizardFileAccess.SetPathVersion(path1, v);

			return path1;
		}

		private string GetPathEnd(string basePath, string path)
		{
			string result = path.Substring(basePath.Length + 1);
			return result;
		}


		private void cmiEditFrom_Click(object sender, EventArgs e)
		{
			try
			{
				Process edit = new Process();

				string fn = _selectedNode.Attributes["FileFullName"].Value;
				string path1 = LizardFileAccess.GetFilePath(null, diffPath1 + fn,
					LizardFileAccess.GetChangesetIdFromVersionText(cmbVersion1.Text), "left");

				string args = "\"" + path1 + "\"";
				ProcessStartInfo psi = new ProcessStartInfo(ServerConnections.DefaultConnection.Settings.EditTool, args);
				psi.UseShellExecute = false;
				edit.StartInfo = psi;
				edit.StartInfo.CreateNoWindow = false;
				edit.Start();
			}
			catch
			{
				MessageBox.Show("Could not launch specified diff utility.", "LizardTF Diff");
			}
		}

		private void cmiEditTo_Click(object sender, EventArgs e)
		{
			try
			{
				Process edit = new Process();

				string fn = _selectedNode.Attributes["FileFullName"].Value;
				string path2 = LizardFileAccess.GetFilePath(null, diffPath2 + fn,
					LizardFileAccess.GetChangesetIdFromVersionText(cmbVersion2.Text), "right");
				string args = "\"" + path2 + "\"";
				ProcessStartInfo psi = new ProcessStartInfo(ServerConnections.DefaultConnection.Settings.EditTool, args);
				psi.UseShellExecute = false;
				edit.StartInfo = psi;
				edit.StartInfo.CreateNoWindow = false;
				edit.Start();
			}
			catch
			{
				MessageBox.Show("Could not launch specified edit utility.", "LizardTF Diff");
			}
		}

		private void cmiShowGnu_Click(object sender, EventArgs e)
		{
			try
			{
				Process diff = new Process();
				string fn = _selectedNode.Attributes["FileFullName"].Value;

				string path1 = RegenerateOriginalPath(diffPath1, fn);
				string path2 = RegenerateOriginalPath(diffPath2, fn);


				string args = "  \"" + path2 + "\" \"" + path1 + "\"";
				ProcessStartInfo psi = new ProcessStartInfo(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\gnu\\diff.exe", args);
				psi.RedirectStandardOutput = true;
				psi.UseShellExecute = false;
				diff.StartInfo = psi;
				diff.StartInfo.CreateNoWindow = true;
				diff.Start();

				string tempFile = ServerConnections.DefaultConnection.Settings.TempPath + "\\diff";
				int i = 0;
				while (File.Exists(tempFile))
				{
					tempFile = ServerConnections.DefaultConnection.Settings.TempPath + "\\diff" + i.ToString();
					i++;
				}
				StreamWriter sw = new StreamWriter(tempFile);
				sw.Write(diff.StandardOutput.ReadToEnd());
				sw.Close();

				Process edit = new Process();

				ProcessStartInfo edpsi = new ProcessStartInfo(ServerConnections.DefaultConnection.Settings.EditTool, tempFile);
				edpsi.UseShellExecute = false;
				edit.StartInfo = edpsi;
				edit.StartInfo.CreateNoWindow = true;
				edit.Start();

			}
			catch
			{
				MessageBox.Show("Could not launch specified gnu diff utility.", "LizardTF Diff");
			}
		}

		private void Form1_Closing(object sender, CancelEventArgs e)
		{
			PersistableHashtable pht = new PersistableHashtable();
			pht.Clear();


			pht.Add("ShowAllPaths", ckbShowAllPaths.Checked.ToString());
			pht.Add("ShowDiffs", ckbShowDiffs.Checked.ToString());
			pht.Add("ShowMissing", ckbShowMissing.Checked.ToString());
			pht.Add("ShowSames", ckbShowSames.Checked.ToString());
			pht.Add("ShowAdded", ckbShowAdded.Checked.ToString());
			pht.Add("ShowDiffMetrics", ckbShowDiffMetrics.Checked.ToString());
			pht.Add("ShowFullPaths", ckbShowFullPaths.Checked.ToString());
			pht.Add("ShowTotals", ckbShowTotals.Checked.ToString());
			pht.Add("UserChecks", ckbUserChecks.Checked.ToString());
			pht.Add("IgnoreBlankLines", ckbIgnoreBlankLines.Checked.ToString());
			pht.Add("IgnoreCase", ckbIgnoreCase.Checked.ToString());
			pht.Add("IgnoreSpaceChanges", ckbIgnoreSpaceChanges.Checked.ToString());
			pht.Add("IgnoreTabExpansions", ckbIgnoreTabExpansions.Checked.ToString());
			pht.Add("IgnoreWhiteSpace", ckbIgnoreWhiteSpace.Checked.ToString());

			pht.Save();
		}


		private void pathBox_DragDrop(object sender, DragEventArgs e)
		{
			string[] sa = (string[])e.Data.GetData(DataFormats.FileDrop);
			string s = sa[0];
			(sender as TextBox).Text = s;

		}

		private void pathBox_DragOver(object sender, DragEventArgs e)
		{
			e.Effect = DragDropEffects.All;
		}

		private void compareToolStripMenuItem_Click(object sender, EventArgs e)
		{
			Compare();
		}

		private void exitToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		private void cbtTFPath1_Click(object sender, EventArgs e)
		{
			TFServerConnection connection;
			GetTFPath(txtPath1, cmbVersion1, workspace1, out connection);
			sselConnection1.Connection = connection;
		}

		private void cbtTFPath2_Click(object sender, EventArgs e)
		{
			TFServerConnection connection;
			GetTFPath(txtPath2, cmbVersion2, workspace2, out connection);
			sselConnection1.Connection = connection;
		}


		private void cmbVersion1_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (inProcessComboBox == sender)
				return;
			ComparePathChanged(txtPath1, cmbVersion1, false);
		}

		private void cmbVersion1_DropDown(object sender, EventArgs e)
		{
			LoadVersions(cmbVersion1, txtPath1.Text, sselConnection1.Connection);
		}

		private void cmbVersion2_DropDown(object sender, EventArgs e)
		{
			LoadVersions(cmbVersion2, txtPath2.Text, sselConnection2.Connection);
		}

		private bool ignoreVersionChanges = false;

		private ComboBox inProcessComboBox = null;

		private void LoadVersions(ComboBox cmbVersion, string path, TFServerConnection connection)
		{
			try
			{
				if (!ignoreVersionChanges)
				{
					ignoreVersionChanges = true;
					inProcessComboBox = cmbVersion;
					LizardFileAccess.LoadVersions(connection, cmbVersion, path);
					ignoreVersionChanges = false;
				}
				//cmbVersion.Items.Clear();
				//cmbVersion.Items.Add("Latest");
				//VersionControlServer vcServer = connection.VersionControlServer;
				//int latestChangesetId = vcServer.GetLatestChangesetId();
				//object history = vcServer.QueryHistory(path, new ChangesetVersionSpec(latestChangesetId), 0, RecursionType.Full, "",
				//  new ChangesetVersionSpec(1), new ChangesetVersionSpec(latestChangesetId), 1000, true, false);
				//System.Collections.IEnumerable changesets = (System.Collections.IEnumerable)history;

				//foreach (Changeset c in changesets)
				//{
				//  cmbVersion.Items.Add(c.ChangesetId);
				//}
			}
			catch
			{

			}
			finally
			{
				inProcessComboBox = null;
			}
		}

		private void txtPath1_Click(object sender, EventArgs e)
		{
			//	ResetVersionCombo(txtPath1, cmbVersion1);
		}

		private void txtPath2_Click(object sender, EventArgs e)
		{
			//	ResetVersionCombo(txtPath2, cmbVersion2);
		}

		private void ComparePathChanged(TextBox txtPath, ComboBox cmbVersion, bool clearCombo)
		{
			if (clearCombo)
				cmbVersion.Items.Clear();

			if (txtPath.Text.StartsWith("$/") && !cmbVersion.Enabled)
			{
				cmbVersion.Text = "Latest";
				cmbVersion.Enabled = true;
			}
			else if (txtPath.Text.StartsWith("$/") && cmbVersion.Enabled)
			{
				cmbVersion.Enabled = true;
			}
			else
			{
				cmbVersion.Text = "n/a";
				cmbVersion.Enabled = false;
			}
			bool allowTrackRenames = false;
			string p1 = txtPath1.Text;
			if (workspace1 != null)
			{
				if (!p1.StartsWith("$"))
					p1 = workspace1.TryGetServerItemForLocalItem(p1);
				string p2 = txtPath2.Text;
				if (!p2.StartsWith("$"))
					p2 = workspace1.TryGetServerItemForLocalItem(p2);

				if (!string.IsNullOrEmpty(p1) && p1 == p2)
				{
					// same repository path!
					allowTrackRenames = true;
				}
			}
			ckbTrackRenames.Visible = allowTrackRenames;
			ckbTrackRenames.Checked = allowTrackRenames;
			cbtViewChangesets.Enabled = allowTrackRenames;
			rbtTFSMerge.Enabled = allowTrackRenames;
			if (!allowTrackRenames)
				rbtLizardMerge.Checked = true;

		}

		private void txtPath1_TextChanged(object sender, EventArgs e)
		{
			ComparePathChanged(txtPath1, cmbVersion1, true);
			if (historySelector1 == null)
				historySelector1 = new HistorySelector(cmbVersion1, sselConnection1.Connection, workspace1);
			historySelector1.Path = txtPath1.Text;
		}

		private void txtPath2_TextChanged(object sender, EventArgs e)
		{
			ComparePathChanged(txtPath2, cmbVersion2, true);
			if (historySelector2 == null)
				historySelector2 = new HistorySelector(cmbVersion2, sselConnection2.Connection, workspace2);
			historySelector2.Path = txtPath2.Text;
		}

		private void chkCompareToLocal_CheckedChanged(object sender, EventArgs e)
		{
			txtPath2.Enabled = !chkCompareToLocal.Checked && !chkFromAsTo.Checked;
			pbConflict.Visible = chkCompareToLocal.Checked;
			lblConflict.Visible = chkCompareToLocal.Checked;
			cmbVersion2.Enabled = !chkCompareToLocal.Checked && txtPath2.Text.StartsWith("$/");
			if (chkCompareToLocal.Checked)
				txtPath2.Text = txtPath1.Text;
		}

		string lastDialogFolder = string.Empty;
		private void menuItem1_Click(object sender, EventArgs e)
		{
			string fn = string.Empty;
			if (_selectedNode.Attributes["FileFullName"] != null)
				fn = _selectedNode.Attributes["FileFullName"].Value;
			else if (_selectedNode.Attributes["DirFullName"] != null)
				fn = _selectedNode.Attributes["DirFullName"].Value;

			OpenFileDialog ofd = new OpenFileDialog();
			ofd.Title = "Select Target File";
			if (lastDialogFolder != string.Empty)
			{
				//			if (File.Exists(Path.Combine(lastDialogFolder, Path.GetFileName(fn))))
				ofd.FileName = Path.Combine(lastDialogFolder, Path.GetFileName(fn));
				//else
				//  ofd.FileName = lastDialogFolder;
			}
			else
				ofd.FileName = Path.GetFileName(fn);
			ofd.ShowDialog();

			if (File.Exists(ofd.FileName))
			{
				lastDialogFolder = (Path.GetDirectoryName(ofd.FileName));

				Show3WayDiff(fn, ofd.FileName);
			}
		}

		private void Show3WayDiff(string fn, string targetName)
		{
			bool cancel = CheckOutFile(targetName, true);

			if (cancel)
				return;

			string path1 = string.Empty;
			string path2 = string.Empty;
			if (diffPath1.StartsWith("$"))
				path1 = LizardFileAccess.GetFilePath(sselConnection1.Connection, diffPath1 + fn,
					LizardFileAccess.GetChangesetIdFromVersionText(mergeVersion1), "mergeleft");
			else
				path1 = LizardFileAccess.GetFilePath(sselConnection1.Connection, diffPath1 + fn);
			if (diffPath2.StartsWith("$"))
				path2 = LizardFileAccess.GetFilePath(sselConnection2.Connection, diffPath2 + fn,
					LizardFileAccess.GetChangesetIdFromVersionText(mergeVersion2), "mergeright");
			else
				path2 = LizardFileAccess.GetFilePath(sselConnection2.Connection, diffPath2 + fn);
			ThreeWayDiff twd = new ThreeWayDiff(path2, path1, targetName);
			twd.ShowDialog();
		}

		private bool CheckOutFile(string targetName, bool askFirst)
		{
			bool cancel = false;
			if (workspace1 != null)
			{
				string serverItem = workspace1.TryGetServerItemForLocalItem(targetName);
				if (serverItem != null)
				{
					ExtendedItem[] extItems = workspace1.GetExtendedItems(new ItemSpec[] { new ItemSpec(serverItem, RecursionType.None) }, DeletedState.Any, ItemType.File)[0];
					if (extItems.Length == 1)
					{
						ExtendedItem extItem = extItems[0];
						if (extItem.ChangeType == ChangeType.None)
						{
							DialogResult dr = DialogResult.Yes;

							if (askFirst)
							{
								dr = MessageBox.Show("Do you wish to check out the target file before merging changes?", "Check Out Target",
									MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
							}

							if (dr == DialogResult.Cancel)
								cancel = true;
							else if (dr == DialogResult.Yes)
							{
								TFServerConnection connection = ServerConnections.GetConnectionForPath(targetName);
								Ltf.Remoting.Operations.WorkspaceOperators wso = new Ltf.Remoting.Operations.WorkspaceOperators(connection, workspace1);
								wso.PendEdit(new string[] { targetName });
							}
						}
					}
				}
			}
			return cancel;
		}

		private void label2_Click(object sender, EventArgs e)
		{

		}

		private void cbtPatch_Click(object sender, EventArgs e)
		{
			CreatePatch();
		}

		public void CreatePatch()
		{
			string[] oldNames = { };
			string[] newNames = { };

			if (ckbTrackRenames.Visible && ckbTrackRenames.Checked)
			{
				string[][] renames = GetRenames();
				oldNames = renames[0];
				newNames = renames[1];

			}

			SaveFileDialog sfd = new SaveFileDialog();

			sfd.Filter = "Diff File (*.diff)|*.diff|Patch File (*.patch)|*.patch";
			sfd.OverwritePrompt = true;
			sfd.RestoreDirectory = true;

			DialogResult dr = sfd.ShowDialog();

			if (dr == DialogResult.OK)
			{
				savePatchOnFinish = true;
				patchFileName = sfd.FileName;
				RunDiffer(true, oldNames, newNames, null);

			}
		}

		private string[][] GetRenames()
		{
			WorkspaceOperators wso = new WorkspaceOperators(sselConnection1.Connection, workspace1);
			string p1 = txtPath1.Text;
			if (!p1.StartsWith("$"))
				p1 = workspace1.TryGetServerItemForLocalItem(p1);

			int vFrom = 0;
			int.TryParse(cmbVersion2.Text, out vFrom);
			int vTo = 0;
			int.TryParse(cmbVersion1.Text, out vTo);

			bool includePends = (!txtPath1.Text.StartsWith("$") || !txtPath1.Text.StartsWith("$"));

			string[][] renames = wso.GetRenames(p1, vFrom, vTo, includePends);
			return renames;
		}

		private void chkToAsFrom_CheckedChanged(object sender, EventArgs e)
		{
			txtPath2.Enabled = !chkCompareToLocal.Checked && !chkFromAsTo.Checked;
			if (chkFromAsTo.Checked)
				txtPath2.Text = txtPath1.Text;

		}

		private void groupBox1_Enter(object sender, EventArgs e)
		{

		}

		private TFHistory currentHistory;
		private Ltf.MonitorLizard.Helpers.FileIcons fileIcons;
		Dictionary<ListView, int> sortColumnIndex;
		Dictionary<ListView, bool> sortDesc;


		public void ShowHistory()
		{
			using (BusyIndicator bi = new BusyIndicator("LizardTF History", "Fetching history from server...", false))
			{
				string p1 = txtPath1.Text;
				if (!p1.StartsWith("$"))
					p1 = workspace1.TryGetServerItemForLocalItem(p1);

				int vFrom = 0;
				int.TryParse(cmbVersion2.Text, out vFrom);
				int vTo = 0;
				int.TryParse(cmbVersion1.Text, out vTo);

				if (sselConnection1.Connection == null)
					sselConnection1.Connection = ServerConnections.DefaultConnection;

				currentHistory = new TFHistory(sselConnection1.Connection, p1, workspace1);
				currentHistory.BranchResolutionType = BranchResolutionType.None;

				currentHistory.GetHistory(true, vTo, vFrom, -1, RecursionType.Full);

				fileIcons = new Ltf.MonitorLizard.Helpers.FileIcons(fileImages);
				sortColumnIndex = new Dictionary<ListView, int>();
				sortColumnIndex.Add(lvwHistory, 0);
				sortDesc = new Dictionary<ListView, bool>();
				sortDesc.Add(lvwHistory, false);

				lvwHistory.StateImageList = fileImages;

				lvwHistory.Items.Clear();
				LoadChangesets();
				ShowSelectedChangesetFiles();
			}
		}

		private void LoadChangesets()
		{
			int lastChangesetId = 0;
			foreach (LizardChangeset lc in currentHistory.Changesets)
			{
				string name = lc.Commiter;
				string[] ps = lc.Commiter.Split('\\');
				if (ps.Length == 2)
					name = ps[1];
				string date = lc.CreationDate.ToString("dd/MM/yy hh:mm");
				ListViewItem lvi = new ListViewItem(new string[] { lc.ChangesetId.ToString(), name, date, lc.Comment, lc.WorkItemIds });
				lvi.Tag = currentHistory.GetChangesetDetails(lc.ChangesetId);

				if (lc.IsFromBranch)
					lvi.ForeColor = Color.Blue;

				lvwHistory.Items.Add(lvi);
				lastChangesetId = lc.ChangesetId;
			}
		}

		void lsvChanges_ColumnClick(object sender, ColumnClickEventArgs e)
		{
			ListView lv = sender as ListView;
			lv.Columns[sortColumnIndex[lv]].ImageKey = null;
			if (sortColumnIndex[lv] == e.Column)
				sortDesc[lv] = !sortDesc[lv];
			else
			{
				sortDesc[lv] = false;
				sortColumnIndex[lv] = e.Column;
			}
			lv.ListViewItemSorter = (IComparer)new Sorter(sortColumnIndex[lv], sortDesc[lv]);
			lv.Sort();

		}

		private void ckbTrackRenames_CheckedChanged(object sender, EventArgs e)
		{

		}

		private void cmbVersion2_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (inProcessComboBox == sender)
				return;
			ComparePathChanged(txtPath2, cmbVersion2, false);
		}

		private void cbtViewChangesets_Click(object sender, EventArgs e)
		{
			ShowHistory();
		}

		private void btnLtfMergeTarget_Click(object sender, EventArgs e)
		{
			FolderBrowserDialog fbd = new FolderBrowserDialog();
			fbd.ShowNewFolderButton = false;
			DialogResult dr = fbd.ShowDialog();
			if (dr == DialogResult.OK)
				txtLtfMergeTarget.Text = fbd.SelectedPath;
		}

		private void rbtTFSMerge_CheckedChanged(object sender, EventArgs e)
		{
			ShowTargetOptions(true);
		}

		private void rbtLizardMerge_CheckedChanged(object sender, EventArgs e)
		{
			ShowTargetOptions(false);
		}

		private void ShowTargetOptions(bool isTFSMerge)
		{
			pnlLtfMergeTarget.Visible = !isTFSMerge;
			cmbTfsMergeTarget.Visible = isTFSMerge;
			string p1 = txtPath1.Text;
			if (workspace1 != null)
			{
				if (!p1.StartsWith("$"))
					p1 = workspace1.TryGetServerItemForLocalItem(p1);
			}

			if (isTFSMerge)
			{
				WorkspaceOperators wso = new WorkspaceOperators(connection1, workspace1);
				string[] targetPaths = wso.GetMergeTargetPaths(p1);
				cmbTfsMergeTarget.DataSource = targetPaths;
			}

		}

		private void cbtPrepareMerge_Click(object sender, EventArgs e)
		{
			if (!rbtLizardMerge.Checked)
			{
				MessageBox.Show("This option is not available when using the native TFS branch merging", "Lizard Merge Only");
				return;
			}

			mergePath1 = txtPath1.Text;
			mergePath2 = txtPath2.Text;
			mergeTargetPath = txtLtfMergeTarget.Text;

			mergeVersion1 = mergeVersion2 = string.Empty;

			if (lvwHistory.SelectedItems.Count == 0)
			{
				if (cmbVersion1.Text != null)
					mergeVersion1 = cmbVersion1.Text;
				if (cmbVersion2.Text != null)
					mergeVersion2 = cmbVersion2.Text;
			}
			else
			{
				int max = int.MinValue, min = int.MaxValue;
				foreach(ListViewItem lvi in lvwHistory.SelectedItems)
				{
					Changeset cs = lvi.Tag as Changeset;
					if (cs!=null)
					{
						if (cs.ChangesetId > max)
							max = cs.ChangesetId;
						if (cs.ChangesetId < min)
							min = cs.ChangesetId;
					}
				}
				mergeVersion2 = min.ToString();
				mergeVersion1 = max.ToString();

				if (mergeVersion1 == int.MinValue.ToString() || mergeVersion1 == int.MaxValue.ToString())
					mergeVersion1 = "0";
				if (mergeVersion2 == int.MinValue.ToString() || mergeVersion2 == int.MaxValue.ToString())
					mergeVersion2 = "0";
			}

			List<string> includedFiles = new List<string>();
			if (lvwDetails.SelectedItems.Count != 0)
			{
				foreach (ListViewItem lvi in lvwDetails.SelectedItems)
				{
					// tag should hold info about files and versions but until then just use the text
					// and don't try this on anything that has been renamed!
					includedFiles.Add(lvi.SubItems[2].Text);
				}
			}
			else if (lvwHistory.SelectedItems.Count !=0)
			{
				foreach (ListViewItem lvi in lvwDetails.Items)
				{
					// tag should hold info about files and versions but until then just use the text
					// and don't try this on anything that has been renamed!
					includedFiles.Add(lvi.SubItems[2].Text);
				}
			}
			//string patchFile = File.ReadAllText("c:\\dryruntest.diff");

			//PrepareMerge(patchFile, txtLtfMergeTarget.Text);


			string[] oldNames = { };
			string[] newNames = { };

			if (ckbTrackRenames.Visible && ckbTrackRenames.Checked)
			{
				string[][] renames = GetRenames();
				oldNames = renames[1];
				newNames = renames[0];

			}

			savePatchOnFinish = false;
			isPrepareMerge = true;
			RunDiffer(true, oldNames, newNames, includedFiles);

		}

		private void lsvMergeResults_DoubleClick(object sender, EventArgs e)
		{
			ListViewHitTestInfo lvhti = lsvMergeResults.HitTest(lsvMergeResults.PointToClient(Form.MousePosition));

			ListViewItem lvi = lvhti.Item;

			if (lvi != null)
			{
				DifferenceInfo di = (DifferenceInfo)lvi.Tag;
				string path1 = mergePath1;
				string fn = "/" + (string.IsNullOrEmpty(di.NewName) ? di.OldName : di.NewName);

				diffPath1 = mergePath1;
				diffPath2 = mergePath2;

				Show3WayDiff(fn, di.ItemTargetPath);
			}

		}

		private int MergeChangeSetVersionFrom
		{
			get { return ChangeSetNumberFromString(mergeVersion2); }
		}

		private int MergeChangeSetVersionTo
		{
			get { return ChangeSetNumberFromString(mergeVersion1); }
		}

		private int ChangeSetNumberFromString(string changeSetString)
		{
			int cs = 0;
			int.TryParse(changeSetString, out cs);
			return cs;
		}

		private void pbSame_Click(object sender, EventArgs e)
		{

		}

		private void btnAutoMerge_Click(object sender, EventArgs e)
		{
			MergeResult result = AutoMergeAll();
			MessageBox.Show(string.Format("Merge completed successfully:\r\nMerged Files : {0}\r\nRenamed Files : {1}\r\nMoved Files : {2}\r\nNew Files : {3}\r\nDeleted Files : {4}\r\nUndeleted Files : {5}\r\n",
			result.MergedFiles, result.RenamedFiles, result.MovedFiles, result.NewFiles, result.DeletedFiles, result.UnDeletedFiles), "Merge Complete", MessageBoxButtons.OK, MessageBoxIcon.None);
		}

		private MergeResult AutoMergeAll()
		{
			MergeResult result = new MergeResult();
			foreach (DifferenceInfo di in diffInfos)
			{
				if (di.Conflicts == 0 && !di.Resolved)
				{
					foreach (MergeCommand mc in di.MergeCommands)
					{
						result += mc.Execute();
					}
					di.Resolved = true;
				}
			}
			ShowAllDiffInfos();
			this.Refresh();
			return result;
		}

		private void btnManualMerge_Click(object sender, EventArgs e)
		{

		}

		private void chkAllChangedFiles_CheckedChanged(object sender, EventArgs e)
		{
			ShowAllDiffInfos();
		}


		private void pcbSlideRight_Click(object sender, EventArgs e)
		{
			SetChangeSetPanelRight();
		}

		private void SetChangeSetPanelRight()
		{
			pcbSlideLeft.Visible = true;
			pcbSlideRight.Visible = false;
			pnlChangeSetFiles.Width = 21;
			pnlChangeSetFiles.Left = gbChangeSets.Width - pnlChangeSetFiles.Width - 8;
			pnlChangeSetFiles.Anchor = AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;
			lvwHistory.Width = pnlChangeSetFiles.Right - lvwHistory.Left - pnlChangeSetFiles.Width;
		}

		private void pcbSlideLeft_Click(object sender, EventArgs e)
		{
			SetChangeSetPanelLeft();
		}

		private void SetChangeSetPanelLeft()
		{
			pcbSlideLeft.Visible = false;
			pcbSlideRight.Visible = true;
			pnlChangeSetFiles.Width = 300;
			pnlChangeSetFiles.Left = gbChangeSets.Width - pnlChangeSetFiles.Width - 14;
			lvwDetails.Width = pnlChangeSetFiles.Width - 22;
			lvwDetails.Anchor = AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left;
			lvwDetails.Visible = true;
			pnlChangeSetFiles.Anchor = AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;
			lvwHistory.Width = pnlChangeSetFiles.Right - lvwHistory.Left - pnlChangeSetFiles.Width;
		}

		private void splitter1_SplitterMoving(object sender, SplitterEventArgs e)
		{
			pcbSlideLeft.Visible = false;
			pcbSlideRight.Visible = true;
			pnlChangeSetFiles.Width = gbChangeSets.Width - e.X;
			pnlChangeSetFiles.Left = gbChangeSets.Width - pnlChangeSetFiles.Width - 8;
			lvwHistory.Width = pnlChangeSetFiles.Right - lvwHistory.Left - pnlChangeSetFiles.Width;
		}

		private void splitter1_SplitterMoved(object sender, SplitterEventArgs e)
		{
		}

		private void splitter1_LocationChanged(object sender, EventArgs e)
		{

		}

		private void splitter1_Move(object sender, EventArgs e)
		{
		}

		private void splitter1_MouseUp(object sender, MouseEventArgs e)
		{
			splitting = false;
		}

		private void splitter1_MouseMove(object sender, MouseEventArgs e)
		{
			if (splitting)
			{
				int x = this.PointToClient(MousePosition).X;
				if (x > 10 && x <= gbChangeSets.Width - 20)
				{
					pcbSlideLeft.Visible = false;
					pcbSlideRight.Visible = true;
					pnlChangeSetFiles.Width = gbChangeSets.Width - x;
					pnlChangeSetFiles.Left = gbChangeSets.Width - pnlChangeSetFiles.Width - 8;
					lvwDetails.Width = pnlChangeSetFiles.Width - 22;
					lvwDetails.Anchor = AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left;
					pnlChangeSetFiles.Anchor = AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;
					lvwHistory.Width = pnlChangeSetFiles.Right - lvwHistory.Left - pnlChangeSetFiles.Width;
					if (x < gbChangeSets.Width - 21)
					{
						pcbSlideLeft.Visible = false;
						pcbSlideRight.Visible = true;
						lvwDetails.Visible = true;
					}
					if (x == gbChangeSets.Width - 20)
					{
						pcbSlideLeft.Visible = true;
						pcbSlideRight.Visible = false;
						lvwDetails.Visible = false;
					}
				}
			}
		}

		bool splitting = false;

		private void splitter1_MouseDown(object sender, MouseEventArgs e)
		{
			splitting = true;
		}

		void changesetListController_AfterMultiSelection(object sender, EventArgs e)
		{
			ShowSelectedChangesetFiles();
		}

		private void ShowSelectedChangesetFiles()
		{
			List<Changeset> changeSets = new List<Changeset>();
			IEnumerable items = null;
			if (lvwHistory.SelectedItems.Count > 0)
				items = lvwHistory.SelectedItems;
			else
				items = lvwHistory.Items;

			foreach (ListViewItem cslvi in items)
			{
				Changeset cs = (Changeset)cslvi.Tag;
				if (cs != null)
				{
					changeSets.Add(cs);
				}
			}
			ShowChangeSetFiles(changeSets);
		}

		private void ShowChangeSetFiles(List<Changeset> changeSets)
		{
			if (changeSets.Count > 0)
			{
				lvwDetails.Items.Clear();
				lvwDetails.SmallImageList = fileImages;
				lvwDetails.StateImageList = fileImages;
				Dictionary<int, ListViewItem> itemsByPath = new Dictionary<int, ListViewItem>();
				int filesOutside = 0;
				foreach (Changeset cs in changeSets)
				{
					foreach (Change c in cs.Changes)
					{
						string serverItem = c.Item.ServerItem;
						if (c.Item.ServerItem.StartsWith(txtPath2.Text))
						{
							int itemId = c.Item.ItemId;
							if (itemsByPath.ContainsKey(itemId))
							{
								ListViewItem lvi = itemsByPath[itemId];
								List<string> changes = new List<string>();
								foreach (string change in lvi.SubItems[1].Text.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries))
									changes.Add(change.Trim());

								foreach (string change in c.ChangeType.ToString().Split(','))
								{
									if (!changes.Contains(change.Trim()))
										lvi.SubItems[1].Text += ", " + change;
								}

								List<string> names = new List<string>(lvi.SubItems[2].Text.Split(','));
								if (!names.Contains(serverItem))
									lvi.SubItems[2].Text += "," + serverItem;

							}
							else
							{
								ListViewItem lvi = new ListViewItem(new string[] { System.IO.Path.GetFileName(serverItem),c.ChangeType.ToString(),
										serverItem});
								lvi.Tag = c.Item.ServerItem;
								if (c.Item.ItemType == ItemType.Folder)
									lvi.ImageKey = "$folder";
								else
									lvi.ImageKey = fileIcons.LoadIconForFileExtension(System.IO.Path.GetExtension(serverItem));
								lvwDetails.Items.Add(lvi);
								itemsByPath.Add(itemId, lvi);
							}
						}
						else
							filesOutside++;
					}
				}
				if (filesOutside == 0)
					lblCSFilesOutsidePath.Text = string.Empty;
				else
					lblCSFilesOutsidePath.Text = string.Format("There are ({0}) files in the selected ChangeSet(s) that are outside the selected path.",filesOutside);

				lvwDetails.ListViewItemSorter = new sorter();
				lvwDetails.Sort();
			}
		}

		private class sorter : IComparer
		{
			#region IComparer<ListViewItem> Members

			public int Compare(object x, object y)
			{
				ListViewItem xLvi = x as ListViewItem;
				ListViewItem yLvi = y as ListViewItem;
				return xLvi.Text.CompareTo(yLvi.Text); ;
			}

			#endregion
		}

		private void DirDiff_Resize(object sender, EventArgs e)
		{

		}

		private void cbtRollbackChangesets_Click(object sender, EventArgs e)
		{

		}
	}
}